package serial

import (
	"fmt"
	"runtime"
	"strconv"
	"strings"

	goserial "gitee.com/haodreams/serial/serial"
)

// Serial 串口
type Serial struct {
	opt goserial.OpenOptions
	//Connect     string //linux 下 COM 会自动替换为/dev/ttyO
	ReadBufSize int   //读取数据的缓冲区
	HaveRecv    bool  //是否开启数据接收线程
	timeoutMS   int64 //超时时间
	TimeoutRWC
}

func NewSerial(opts ...Option) *Serial {
	m := new(Serial)
	m.Setup(opts...)
	return m
}

func (m *Serial) Setup(opts ...Option) {
	m.timeoutMS = 1000
	m.HaveRecv = true
	for _, f := range opts {
		f(m)
	}
	m.ReadBufSize = min(max(m.ReadBufSize, 64), 65535)
	m.TimeoutRWC.Setup(nil, m.ReadBufSize, m.timeoutMS)
}

func (m *Serial) OptionString() string {
	parity := "N"
	switch m.opt.ParityMode {
	case goserial.PARITY_NONE:
		parity = "N"
	case goserial.PARITY_ODD:
		parity = "O"
	case goserial.PARITY_EVEN:
		parity = "E"
	}
	return fmt.Sprintf("%s,%d,%s,%d,%d", m.opt.PortName, m.opt.BaudRate, parity, m.opt.DataBits, m.opt.StopBits)
}

// Open 打开
func (m *Serial) Open() (err error) {
	conn, err := goserial.Open(m.opt)
	if err != nil {
		return
	}
	if conn == nil {
		err = fmt.Errorf("'%s' open failed", m.OptionString())
		return
	}
	m.TimeoutRWC.SetRWC(conn)
	return
}

type Option func(*Serial)

// 单位毫秒
func WithTimeout(ms int64) Option {
	return func(m *Serial) {
		m.timeoutMS = ms
	}
}

// 设置连接字符串
func WithConnect(conn string) Option {
	return func(m *Serial) {
		if len(conn) > 3 {
			if runtime.GOOS == "windows" {
				if strings.HasPrefix(conn, "/dev/tty") {
					pos := strings.IndexFunc(conn, func(c rune) bool {
						if c >= '0' && c <= '9' {
							return true
						}
						return false
					})
					if pos > 0 {
						conn = "COM" + conn[pos:]
					}
				}
			}
		}
		//默认9600,N,8,1,5000
		m.opt.InterCharacterTimeout = 5000 //ms
		m.opt.InterCharacterTimeout = 0    //ms
		m.opt.MinimumReadSize = 1
		m.opt.BaudRate = 9600
		m.opt.ParityMode = goserial.PARITY_NONE
		m.opt.DataBits = 8
		m.opt.StopBits = 1

		opt := strings.Replace(conn, " ", "", -1)
		s := strings.Split(opt, ",")
		if len(s) < 1 {
			panic("串口选项配置错误")
		}
		m.opt.PortName = s[0]
		if len(s) > 1 {
			ival, err := strconv.Atoi(s[1])
			if err != nil {
				return
			}
			m.opt.BaudRate = uint(ival) //9600
		}
		if len(s) > 2 {
			switch s[2] {
			case "n", "N":
				m.opt.ParityMode = goserial.PARITY_NONE
			case "e", "E":
				m.opt.ParityMode = goserial.PARITY_EVEN
			case "o", "O":
				m.opt.ParityMode = goserial.PARITY_ODD
			}
		}

		if len(s) > 3 {
			ival, err := strconv.Atoi(s[3])
			if err != nil {
				panic("DataBits error," + err.Error())
			}
			m.opt.DataBits = uint(ival)
		}

		if len(s) > 4 {
			switch s[4] {
			case "1":
				m.opt.StopBits = 1
			case "2":
				m.opt.StopBits = 2
			}
		}
		// if len(s) > 5 {
		// 	timeout, err := strconv.Atoi(s[5])
		// 	if err != nil {
		// 		return
		// 	}

		// 	//timeout = min(max(timeout, 100), 60000)
		// 	//m.opt.InterCharacterTimeout = uint(timeout)
		// }
	}
}

// 设置读取缓冲区的大小
func WithReadBufferSize(size int) Option {
	return func(m *Serial) {
		if size < 256 {
			size = 256
		}
		m.ReadBufSize = size
	}
}
